﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows.Threading;
using System.Xml.Linq;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Crm.Sdk.Messages;

namespace VisualRibbonEditor
{
	public class BaseRibbon
	{
		public XElement RibbonXml { get; set; }

		public void LoadAsync(string entityName, Action callback)
		{
			Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
			BackgroundWorker worker = new BackgroundWorker();
			worker.DoWork += (sender, e) =>
				{
					Action threadSafeCallback = () =>
					{
						dispatcher.BeginInvoke(callback);
					};

					try
					{
						Load(entityName, threadSafeCallback);
					}
					catch (Exception ex)
					{
						Action showErrorAction = () => { MainWindow.CurrentMainPage.ShowError(ex); };
						dispatcher.Invoke(showErrorAction);
					}
				};
			worker.RunWorkerAsync();
		}

		public void Load(string entityName, Action loadCompletedCallback)
		{
			OrgRequest req = null;

			if (entityName == "application")
			{
				req = new OrgRequest("RetrieveApplicationRibbon");
			}
			else
			{
				req = new OrgRequest("RetrieveEntityRibbon");
				req.Parameters.Add("EntityName", entityName);
				req.Parameters.Add("RibbonLocationFilter", RibbonLocationFilters.All);
			}
			
			ServiceWrapper svc = Helpers.GetOrgService();
			svc.ExecuteAsync(req.ToOrganizationRequest(), (response) =>
			{
				string dataAttributeName = entityName == "application" ? "CompressedApplicationRibbonXml" : "CompressedEntityXml";
				byte[] zipped = (byte[])response.Results[dataAttributeName];
				MemoryStream ms = new MemoryStream(zipped);

				Dictionary<string, byte[]> files = ExtractZipFile(ms);
				byte[] ribbonXmlData = files["RibbonXml.xml"];

				string text = System.Text.Encoding.UTF8.GetString(ribbonXmlData, 0, ribbonXmlData.Length);

				RibbonXml = XElement.Parse(text);

				loadCompletedCallback.Invoke();
			});
		}

 
		private Dictionary<string,byte[]> ExtractZipFile(Stream fs)
		{
			Dictionary<string, byte[]> files = new Dictionary<string, byte[]>();
			
			ZipFile zf = null;
			try
			{
				zf = new ZipFile(fs);

				foreach (ZipEntry zipEntry in zf)
				{
					if (!zipEntry.IsFile)
					{
						continue;// Ignore directories
					}

					String entryFileName = zipEntry.Name;

					Stream zipStream = zf.GetInputStream(zipEntry);

					MemoryStream ms = new MemoryStream();
					StreamUtils.Copy(zipStream, ms, new byte[4095]);
					files.Add(entryFileName, ms.ToArray());

				}

				return files;
			}
			finally
			{
				if (zf != null)
				{
					zf.IsStreamOwner = true; // Makes close also shut the underlying stream
					zf.Close(); // Ensure we release resources
				}
			}
		}
	}
}
